
#include "Camera.h"

#include <vcl.h>
#include "Camera.h"
#pragma package(smart_init)

#include "gl\gl.h"
#include "gl\glu.h"




Camera::Camera (VectorPoint3D* eye, VectorPoint3D* look, VectorPoint3D *up) {
	n = new VectorPoint3D();
	u = new VectorPoint3D();
	v = new VectorPoint3D();

	setView(eye, look, up);

	left   = 200;
	right  = 0;
	top    = 0;
	bottom = 0;
	cerca  = 0;
	lejos  = 0;
	angulo = 0;
	ratio  = 0;
}

void Camera::setCameraState(type_camera_state state) {
    camera_state = state;
}

type_camera_state Camera::getCameraState() {
    return camera_state;
}

Camera::~Camera(){
    delete eye;
    delete look;
    delete up;
}

void Camera::setView(VectorPoint3D * ojo, VectorPoint3D* mira, VectorPoint3D* arriba){
    glMatrixMode(GL_MODELVIEW);
    eye  = new VectorPoint3D (ojo->getX(), ojo->getY(), ojo->getZ()) ;
    look = new VectorPoint3D(mira->getX(), mira->getY(), mira->getZ()) ;
    up   = new VectorPoint3D(arriba->getX(), arriba->getY(), arriba->getZ()) ;

    n->setX(eye->getX() - look->getX());
    n->setY(eye->getY() - look->getY());
    n->setZ(eye->getZ() - look->getZ());
    n->normalice();


    u = up->prodVectorial(n);
    u->normalice();

    v = n->prodVectorial(u);


    glLoadIdentity();
    gluLookAt(ojo->getX(),ojo->getY(),ojo->getZ(),
        mira->getX(),mira->getY(),mira->getZ(),
        arriba->getX(),arriba->getY(),arriba->getZ());
}

void Camera::resetView() {
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(eye->getX(),eye->getY(),eye->getZ(),
        look->getX(),look->getY(),look->getZ(),
        up->getX(),up->getY(),up->getZ());

    n->setX(eye->getX() - look->getX());
    n->setY(eye->getY() - look->getY());
    n->setZ(eye->getZ() - look->getZ());
    n->normalice();

    u = up->prodVectorial(n);
    u->normalice();

    v = n->prodVectorial(u);
}


void Camera::roll(float angulo){
	float coseno = cos(((M_PI)/180.0)*angulo);
	float seno   = sin(((M_PI)/180.0)*angulo);

	VectorPoint3D * uaux = new VectorPoint3D();
	uaux->setPunto(u);

	VectorPoint3D * vaux = new VectorPoint3D();
	vaux->setPunto(v);

	u->setX(coseno*uaux->getX( )+seno*vaux->getX());
	u->setY(coseno*uaux->getY( )+seno*vaux->getY());
	u->setZ(coseno*uaux->getZ( )+seno*vaux->getZ());

	v->setX(-seno*uaux->getX( )+coseno*vaux->getX());
	v->setY(-seno*uaux->getY( )+coseno*vaux->getY());
	v->setZ(-seno*uaux->getZ( )+coseno*vaux->getZ());

	setModelViewMatrix();

	delete uaux;
	delete vaux;

}

void Camera::yaw(float angulo){
	float coseno = cos(((M_PI)/180.0)*angulo);
	float seno   = sin(((M_PI)/180.0)*angulo);

	VectorPoint3D * uaux = new VectorPoint3D();
	uaux->setPunto(u);

	VectorPoint3D * naux = new VectorPoint3D();
	naux->setPunto(n);

	n->setX(coseno*naux->getX( ) - seno*uaux->getX());
	n->setY(coseno*naux->getY( ) - seno*uaux->getY());
	n->setZ(coseno*naux->getZ( ) - seno*uaux->getZ());

	u->setX(coseno*uaux->getX( ) + seno*naux->getX());
	u->setY(coseno*uaux->getY( ) + seno*naux->getY());
	u->setZ(coseno*uaux->getZ( ) + seno*naux->getZ());

	setModelViewMatrix();

	delete uaux;
	delete naux;
}

void Camera::pitch(float angulo){
	float coseno = cos(((M_PI)/180.0)*angulo);
	float seno   = sin(((M_PI)/180.0)*angulo);

	VectorPoint3D * vaux = new VectorPoint3D();
	vaux->setPunto(v);

	VectorPoint3D * naux = new VectorPoint3D();
	naux->setPunto(n);

	v->setX(coseno*vaux->getX( ) + seno*naux->getX());
	v->setY(coseno*vaux->getY( ) + seno*naux->getY());
	v->setZ(coseno*vaux->getZ( ) + seno*naux->getZ());

	n->setX(coseno*naux->getX( ) - seno*vaux->getX());
	n->setY(coseno*naux->getY( ) - seno*vaux->getY());
	n->setZ(coseno*naux->getZ( ) - seno*vaux->getZ());

	setModelViewMatrix();

	delete vaux;
	delete naux;
}

void Camera::desplazar(float distancia, int eje) {
	switch(eje){
		case 1:{
			look->setX(look->getX() + distancia*n->getX() );
			look->setY(look->getY() + distancia*n->getY() );
			look->setZ(look->getZ() + distancia*n->getZ() );
			eye->setX(eye->getX() + distancia*n->getX() );
			eye->setY(eye->getY() + distancia*n->getY() );
			eye->setZ(eye->getZ() + distancia*n->getZ() );

			break;
		}

		case 2:{
			look->setX(look->getX() + distancia*u->getX() );
			look->setY(look->getY() + distancia*u->getY() );
			look->setZ(look->getZ() + distancia*u->getZ() );
			eye->setX(eye->getX() + distancia*u->getX() );
			eye->setY(eye->getY() + distancia*u->getY() );
			eye->setZ(eye->getZ() + distancia*u->getZ() );
			break;
		}

		case 3:{
			look->setX(look->getX() + distancia*v->getX() );
			look->setY(look->getY() + distancia*v->getY() );
			look->setZ(look->getZ() + distancia*v->getZ() );
			eye->setX(eye->getX() + distancia*v->getX() );
			eye->setY(eye->getY() + distancia*v->getY() );
			eye->setZ(eye->getZ() + distancia*v->getZ() );
			break;
		}
	}
}

void Camera::ortogonal(){
	left = -100;
	right = 100;
	bottom = -100;
	top = 100;
	cerca= 1;
	lejos= 1000;
	angulo = 15.0;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(this->left , this->right , this->bottom , this->top , this->cerca , this->lejos);
	setModelViewMatrix();
}


void Camera::perspectiva(){
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(90,1,1,1000);
	glOrtho(this->left,this->right,this->bottom,this->top,this->cerca,this->lejos);
}

//---------------------------------------------------------------------------

void Camera::oblicua(VectorPoint3D* d){
    glOrtho(this->left,this->right,this->bottom,this->top,this->cerca,this->lejos);
    if (d->getX()==0 || d->getY()==0 || d->getZ()==0) return;

    float m[16];

	// inicializar matriz identidad
	for (int i=0;i<16;i++) {
		if (i%5==0)
			m[i]=1.0;
		else
			m[i]=0.0;
	}

	m[8] = -d->getX() / d->getZ();
	m[9] = -d->getY() / d->getZ();

	glMultMatrixf(m);
}


void Camera::setModelViewMatrix(){
	V[0]= u->getX() ; V[1]= v->getX() ; V[2] = n->getX() ; V[3] = 0.0;
	V[4]= u->getY() ; V[5]= v->getY() ; V[6] = n->getY() ; V[7] = 0.0;
	V[8]= u->getZ() ; V[9]= v->getZ() ; V[10]= n->getZ() ; V[11]= 0.0;

	V[12] =-eye->prodEscalar(u);
	V[13] =-eye->prodEscalar(v);
	V[14] =-eye->prodEscalar(n);
	V[15] = 1.0;

	glMatrixMode(GL_MODELVIEW);

	glLoadIdentity();
	glLoadMatrixf(V);
}

void Camera::setLimites(float left, float right, float bottom, float top, float cerca, float lejos) {
    this->left = left;
    this->right = right;
    this->bottom = bottom;
    this->top = top;
    this->cerca = cerca;
    this->lejos = lejos;
};

